## Use VCF outputs. This is unnecessary.

# Create a bash script to extract mutation information from Slim output files using perl

sink(paste0("~/Projects/SLiM/extractMutaions.sh"))
gentime<-c(1000,1005,1010,1020)
filename<-"nonWF_neutral1.txt"
modelname<-c("nonWF")
for (i in 1: length(gentime)){
    cat(paste0("perl -lne 'if(/OUT: ",gentime[i]," SS p1 200/../Genome/){s/.*?(OUT: ",gentime[i]," SS p1 200)/$1/ if!$i++;s/Genome\K.*//&&print&&exit;print}' ", filename, "  > mut",i,"\n"))
    cat(paste0("sed '$d' mut",i," > ",modelname,i,".txt\n"))
}
sink(NULL)

1 Allele frequency changes over time (neutral simulations)

2 Temporal Covariance Analysis

2.1 Data processing: Subsampled individuals

  1. Create sample names files for the generated VCF files
#1. Fixed number of individuals

#Select the number of time points and number of samples (individuals)
t=10
n=100

#Create a name file to rename the samples in vcf
for (i in 1:t){
    df<-data.frame(sample=paste0("time",i-1,".",1:n))
    write.table(df, paste0("~/Projects/SLiM/PacHerring/newsampleids.",i-1,".txt"), row.names = F, col.names = F, quote = F)
}


#2. the Entire population
#number of time period
t=10
log<-read.csv("~/Projects/SLiM/PacHerring/nonWF_neutral_log2.txt")
times<-seq(1000, 1000+10*(t-1), 10) 
#Create a name file to rename the samples in vcf
for (i in 1:t){
    n<-log$num_individuals[log$generation==times[i]]
    df<-data.frame(sample=paste0("time",i-1,".",1:n))
    write.table(df, paste0("~/Projects/SLiM/PacHerring/newsampleids.",i-1,".txt"), row.names = F, col.names = F, quote = F)
}
  1. Create a bash script to process Slim VCF files
#Create the bash script to reformat the output of slim
#select the appropriate name
run<-"nonWF.K10000.sub100"  #select a name
model<-"nonWF"
run<-"WF.N10000.sub100"  #select a name
model<-"WF"
run<-"WF.N1000.sub100.Pos0.2.g5000" 

t<-10
all<-'' # ('all' or '' none)

# 1. Create a bash script
sink(paste0("~/Projects/SLiM/PacHerring/slim_",run,".sh"))
cat("#!/bin/bash \n\n")
cat(paste0("mkdir ", run, " \n"))
#rename the samples
for (i in 1:t){
    cat(paste0("bcftools reheader ",model,all,"_time",i-1,".vcf -s newsampleids.",i-1,".txt -o ",run,"/",model,"_time",i-1,".vcf \n"))
}

cat(paste0("cd ",run," \n"))
cat("for f in *.vcf; do filename=$(basename $f); bgzip $f ; done \n")
cat("for f in *.vcf.gz; do filename=$(basename $f); bcftools index $f ; done \n")
#find intersecting loci
cat(paste0("bcftools isec -n=",t," -p isec --threads 10 *vcf.gz \n"))
cat(paste0("bcftools merge *vcf.gz -o ",model,"_combined.vcf.gz \n"))
cat(paste0("bcftools index ",model,"_combined.vcf.gz \n"))
# extract intersec loci from the combined 
cat(paste0("bcftools view -R isec/sites.txt ",model,"_combined.vcf.gz -Oz > ",model,"_isec.vcf.gz \n"))
cat(paste0("rm isec/*.vcf"))
sink(NULL)

## Run  bash slim_xxxx.sh

3 Results from temporal covariance analysis

  • Need to randomly permute the tracked allele (draw a Bernoulli random variable and if it’s 1 you randomly flip the frequency) to avoid bias

Functions to create covariance summary plots

# function to read the covariance output file form cvtkpy with 4 time points, simulation pws pops
# fname=file name, model= "WF" or "nonWF", t=# of time points)
require("stringr")
covResults<-function(fname, model, t){
    cov<-read.csv(paste0("~/Projects/Pacherring_Vincent/slim/",fname))
    cov<-cov[,-1]
    #reshape the matrix
    mat1<-cov[1:(t-1),]
    mat2<-cov[t:(2*t-2),]
    
    covdf<-data.frame()
    k=1
    for (i in 1:nrow(mat1)){
        for (j in 1:ncol(mat1)){
         covdf[k,1]<-mat2[i,j]
         covdf[k,2]<-mat1[i,j]
         k=k+1
        }
    }
    colnames(covdf)<-c("label","value")
    covdf$value<-as.numeric(covdf$value)
    covar<-covdf[grep("cov",covdf$label),]
            
    #remove the redundant values
    ids<-str_match(covar$label, "sim:\\s(.*?)\\,\\ssim:\\s(.*?)\\)")
    ids<-ids[,2:3]
    remove<-duplicated(lapply(1:nrow(ids), function(x) {
        A<-ids[x,]
        A[order(A)]
    }  ))
    covar<-covar[!remove,] 
    
    #assign the starting time period and covering period values
    vecn<-1:(t-2)
    syr<-c()
    for (i in 1:length(vecn)){
        syr<-c(syr, rep(i, times=(t-i-1)))
    }
    covar$start_year<-syr
    
    eyr<-c()
    for (i in 1:(t-2)){
        v<-(i+1):(t-1)
        eyr<-c(eyr,v)
    }
    covar$end_year<-eyr

    newfile<-gsub(".csv","", fname)
    newfile<-gsub("_temp_cov_matrix","", newfile)
    ggplot(data=covar, aes(x=end_year, y=value,group=start_year, color=factor(start_year)))+
        geom_point(size=3)+
        geom_line()+
        ylab("Covariance")+xlab('')+theme_classic()+
        theme(axis.text.x = element_blank(),legend.title = element_blank())+
        geom_hline(yintercept = 0,color="gray70", size=0.3)+ggtitle(paste0(model))+
        scale_y_continuous(labels = scales::comma, limits = c(-0.001,0.001))
    ggsave(paste0("../Output/COV/Sim/", newfile, "_neutral.png"),width = 6, height = 3, dpi=300)
    print(paste0("../Output/COV/Sim/", newfile, "_neutral.png"))
}

#No ylim
covResults2<-function(fname, model, t){
    cov<-read.csv(paste0("~/Projects/Pacherring_Vincent/slim/",fname))
    cov<-cov[,-1]
    #reshape the matrix
    mat1<-cov[1:(t-1),]
    mat2<-cov[t:(2*t-2),]
    
    covdf<-data.frame()
    k=1
    for (i in 1:nrow(mat1)){
        for (j in 1:ncol(mat1)){
         covdf[k,1]<-mat2[i,j]
         covdf[k,2]<-mat1[i,j]
         k=k+1
        }
    }
    colnames(covdf)<-c("label","value")
    covdf$value<-as.numeric(covdf$value)
    covar<-covdf[grep("cov",covdf$label),]
            
    #remove the redundant values
    ids<-str_match(covar$label, "sim:\\s(.*?)\\,\\ssim:\\s(.*?)\\)")
    ids<-ids[,2:3]
    remove<-duplicated(lapply(1:nrow(ids), function(x) {
        A<-ids[x,]
        A[order(A)]
    }  ))
    covar<-covar[!remove,] 
    
    #assign the starting time period and covering period values
    vecn<-1:(t-2)
    syr<-c()
    for (i in 1:length(vecn)){
        syr<-c(syr, rep(i, times=(t-i-1)))
    }
    covar$start_year<-syr
    
    eyr<-c()
    for (i in 1:(t-2)){
        v<-(i+1):(t-1)
        eyr<-c(eyr,v)
    }
    covar$end_year<-eyr

    newfile<-gsub(".csv","", fname)
    newfile<-gsub("_temp_cov_matrix","", newfile)
    ggplot(data=covar, aes(x=end_year, y=value,group=start_year, color=factor(start_year)))+
        geom_point(size=3)+
        geom_line()+
        ylab("Covariance")+xlab('')+theme_classic()+
        theme(axis.text.x = element_blank(),legend.title = element_blank())+
        geom_hline(yintercept = 0,color="gray70", size=0.3)+ggtitle(paste0(model))+
        scale_y_continuous(labels = scales::comma)
    ggsave(paste0("../Output/COV/Sim/", newfile, "_neutral_noylim.png"),width = 6, height = 3, dpi=300)
    print(paste0("../Output/COV/Sim/", newfile, "_neutral_noylim.png"))
}

3.1 Use the entire population to calculate COV and AF (no subsampling of individuals)

3.1.1 WF neutral (all individuals, 10 timepoints)

covResults("Slim_WF_N1000_noCnoS_temp_cov_matrix_250kwin.csv", "WF neutral all (N=1000)", 10)

WF

3.1.2 WF with nonWF model, neutral (all individuals, 10 timepoints)

covResults("Slim_WFnonwf_K1000_noCnoS_temp_cov_matrix_250kwin.csv", "WFnonwf neutral all (K=1000)", 10)

WF

3.1.3 nonWF neutral (K=1000, all individuals, 10 timepoints)

#covResults("Slim_nonWF_all_K1000_t10_temp_cov_matrix_250kwin.csv", "nonWF neutral all (K=1000)", 10)
covResults("Slim_nonWF_K1000_noCnoS_temp_cov_matrix_250kwin.csv", "nonWF neutral all (K=1000, noCnoS)", 10)

covResults("Slim_nonWF_K1000_wCwS_temp_cov_matrix_250kwin.csv", "nonWF neutral all (K=1000)", 10)
[1] "../Output/COV/Sim/Slim_nonWF_K1000_wCwS_250kwin_neutral.png"

3.2 Subsampling 100 individuals from a population (N=1000): no correction

3.2.1 WF (N=1000, sub100) -no bias correction applied

covResults2("Slim_WF_N1000_sub100.v2_noCnoS_temp_cov_matrix_250kwin.csv", "WF neutral (sampled 100, no correction)", 10)

  • Set Y-axis to -0.001 - 0.001:

3.2.2 WF (N=1000, sub100) with bias correction applied

3.2.3 WF with nonWF model (K=1000, sub=100) -no bias correction

3.2.4 WF with nonWF model (K=1000, sub=100) -with bias correction

3.2.5 nonWF model (K=1000, sub=100) -no bias correction

3.2.6 nonWF model (K=1000, sub=100) -with bias correction

3.2.7 WF N=100 entire population

WF

3.3 Sample 1000 individuals from N=10000 population

3.3.1 WF neutral N=10000, sub=1000 (no bias correction, no standardization)

```r
#covResults2(\Slim_WF_N10000_sub1000_noCnoS_temp_cov_matrix_250kwin.csv\, \WF neutral (N=10000

3.3.2 WF neutral N=10000, sub=1000 with bias correction

```r
covResults2(\Slim_WF_N10000_sub1000_wCwS_temp_cov_matrix_250kwin.csv\, \WF neutral(N=10000

3.3.3 WF neutral N=10000, sub=1000 (no bias correction, with standardization)

covResults("Slim_WF_N10000_sub1000_noCwS_temp_cov_matrix_250kwin.csv", "WF neutral all (N=10000, sub=1000) noCwS", 10)
[1] "../Output/COV/Sim/Slim_WF_N10000_sub1000_noCwS_250kwin_neutral.png"

{width=70%}

covResults("Slim_WF_N10000_s100_noCwS_temp_cov_matrix_250kwin.csv", "WF neutral (N=10000, sub=100) noCwS", 10)
[1] "../Output/COV/Sim/Slim_WF_N10000_s100_noCwS_250kwin_neutral.png"

covResults("Slim_nonWF_K10000_s100_noCnoS_temp_cov_matrix_250kwin.csv", "nonWF neutral (K=10000, sub=100) noCnoS", 10)
[1] "../Output/COV/Sim/Slim_nonWF_K10000_s100_noCnoS_250kwin_neutral.png"

3.3.4 Adding beneficial mutaiton

covResults("Slim_WF_N1000_s100_noCwS_Pos0.1_temp_cov_matrix_250kwin.csv", "WF with Positive muts(0.1) (N=1000, sub=100) noCwS", 10)
[1] "../Output/COV/Sim/Slim_WF_N1000_s100_noCwS_Pos0.1_250kwin_neutral.png"

covResults("Slim_WF_N1000_s100_noCwS_Pos0.2_g5000_temp_cov_matrix_250kwin.csv", "WF with Positive(0.2) (N=1000, sub=100) noCwS", 10)
[1] "../Output/COV/Sim/Slim_WF_N1000_s100_noCwS_Pos0.2_g5000_250kwin_neutral.png"

covResults("Slim_WF_N1000_s100_wCnoS_Pos0.2_g5000_temp_cov_matrix_250kwin.csv", "WF with Positive(0.2) (N=1000, sub=100) noCnoS", 10)
[1] "../Output/COV/Sim/Slim_WF_N1000_s100_wCnoS_Pos0.2_g5000_250kwin_neutral.png"

covResults("Slim_WF_N1000_s100_wCnoS_Pos0.2_g5000_temp_cov_matrix_250kwin.csv", "WF with Positive(0.2) (N=1000, sub=100) noCnoS", 10)


3.4 Actual data for 3 populations

4 Estiamte Ne from simulation results

require(data.table)
require(boot)
source("../Rscripts/calcNe.R")

#AF data (using flip data)
wf<-fread("~/Projects/pacherring_Vincent/slim/AF_WF_N10000_s100_flip.csv")
nonwf<-fread("~/Projects/pacherring_Vincent/slim/AF_nonWF_K10000_s100.csv")
setnames(wf, paste0("time",0:9))
setnames(nonwf, paste0("time",0:9))

comb<-data.frame(t1=paste0("time",0:8), t2=paste0("time",1:9))


df <- df1[df2, .(chromo, position, freq1, freq2, nInd1, nInd2)][!is.na(freq1) & !is.na(freq2) & freq1 > 0.1 & freq2 > 0.1, ]
    g=gens[i]
    
    estNe$Ne[i]<-df[, jrNe2(freq1, freq2, nInd1, nInd2, g)] 

estNe<-data.frame(pop1=comb[,1], pop2=comb[,2])
gens<-

for (i in 1: nrow(comb)){
    df1<-wf[,i:(i+1)]
    df1<-apply(df1, 1, function(x) 1-x)
    df1<-data.table(t(df1))
    
    df2<-nonwf[,i:(i+1)]
    
    setnames(df1, 1:2, c("freq1", "freq2"))
    setnames(df2, 1:2, c("freq1", "freq2"))
    
    df1$nInd1<-100
    df1$nInd2<-100
    df2$nInd1<-100
    df2$nInd2<-100
    
    df <- df1[freq1 > 0.1 & freq2 > 0.1,]
    g=10
    
    df[, jrNe2(freq1, freq2, nInd1, nInd2, g)] 

    
    
    estNe$Ne[i]<-df[, jrNe2(freq1, freq2, nInd1, nInd2, g)] 

    # block bootstrapping across LGs
    uq.ch <- df[, sort(unique(chromo))]

    boot.re <- boot(uq.ch, jrNe2block, 1000, gen = g, alldata = df)
    estNe$median[i]<-median(boot.re$t[is.finite(boot.re$t)]) # median bootstrap
    estNe$mean[i]<-mean(boot.re$t[is.finite(boot.re$t)])
    ci<-boot.ci(boot.re, type = c('perc'))
    #95% C.I.
    estNe$CI.low[i]<-ci$percent[4]
    estNe$CI.up[i]<-ci$percent[5]
    
    #reset the attibutes
    setnames(df1, c("freq1", 'nInd1'),c("knownEM", 'nInd'))
    setnames(df2, c("freq2", 'nInd2'),c("knownEM", 'nInd'))
}

write.csv(estNe,"../Output/Ne/Jorde-Ryman_Ne.estimates_PWS.csv")

#estNe<-read.csv("../Output/Ne/Jorde-Ryman_Ne.estimates_PWS.csv", row.names = 1)
estNe$year<-apply(estNe["pop2"],1, function(x) {if (x=="96") x=1996
                   else if (x=="07") x=2007
                   else if (x=="17") x=2017})

ggplot(estNe[c(1,4,6),], aes(x=year, y=Ne))+
    geom_point(size=2, color="blue")+
    geom_errorbar(aes(ymin = CI.low, ymax = CI.up), width = 0.2, color="blue")+
    geom_path(color="blue")+ylab("Estiamted Ne")+xlab("Year")+
    theme_classic()+ggtitle("PWS")
ggsave("../Output/Ne/Jorde-Ryman_Ne.estimates.png", width = 5, height = 3, dpi=300)
knitr::kable(estNe)
LS0tCnRpdGxlOiAiU0xpTSBSZXN1bHRzIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgICAgdG9jOiB0cnVlIAogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICAgIHRoZW1lOiBsdW1lbgogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgICBkZl9wcmludDogcGFnZWQKCi0tLQpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpzb3VyY2UoIi4uL1JzY3JpcHRzL0Jhc2VTY3JpcHRzLlIiKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoY293cGxvdCkKYGBgCgoKCmBgYHtSIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIFVzZSBWQ0Ygb3V0cHV0cy4gVGhpcyBpcyB1bm5lY2Vzc2FyeS4KCiMgQ3JlYXRlIGEgYmFzaCBzY3JpcHQgdG8gZXh0cmFjdCBtdXRhdGlvbiBpbmZvcm1hdGlvbiBmcm9tIFNsaW0gb3V0cHV0IGZpbGVzIHVzaW5nIHBlcmwKCnNpbmsocGFzdGUwKCJ+L1Byb2plY3RzL1NMaU0vZXh0cmFjdE11dGFpb25zLnNoIikpCmdlbnRpbWU8LWMoMTAwMCwxMDA1LDEwMTAsMTAyMCkKZmlsZW5hbWU8LSJub25XRl9uZXV0cmFsMS50eHQiCm1vZGVsbmFtZTwtYygibm9uV0YiKQpmb3IgKGkgaW4gMTogbGVuZ3RoKGdlbnRpbWUpKXsKICAgIGNhdChwYXN0ZTAoInBlcmwgLWxuZSAnaWYoL09VVDogIixnZW50aW1lW2ldLCIgU1MgcDEgMjAwLy4uL0dlbm9tZS8pe3MvLio/KE9VVDogIixnZW50aW1lW2ldLCIgU1MgcDEgMjAwKS8kMS8gaWYhJGkrKztzL0dlbm9tZVxLLiovLyYmcHJpbnQmJmV4aXQ7cHJpbnR9JyAiLCBmaWxlbmFtZSwgIiAgPiBtdXQiLGksIlxuIikpCiAgICBjYXQocGFzdGUwKCJzZWQgJyRkJyBtdXQiLGksIiA+ICIsbW9kZWxuYW1lLGksIi50eHRcbiIpKQp9CnNpbmsoTlVMTCkKYGBgCgojIEFsbGVsZSBmcmVxdWVuY3kgY2hhbmdlcyBvdmVyIHRpbWUgKG5ldXRyYWwgc2ltdWxhdGlvbnMpIAoKYGBge1IgZXZhbD1GQUxTRSwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIzIwMCBnZW5vbWVzICgxMDAgaW5kaXZpZHVhbHMpIGF0IGdlbmVyYXRpb24gMTAwMCwxMDA1LDEwMTAsMTAyMCAKCnRpbWU8LWMoMTAwMCwxMDA1LDEwMTAsMTAyMCkKcmVzdWx0czwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOjQpewogICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCJ+L1Byb2plY3RzL1NMaU0vUGFjSGVycmluZy9ub25XRl9tdXRhdGlvbiIsaSwiLnR4dCIpLCBza2lwPTIpCiAgICAgICAgZGYkQUY8LWRmJFY5LzIwMAogICAgICAgIGRmJHRpbWU8LXRpbWVbaV0KICAgICAgICByZXN1bHRzPC1yYmluZChyZXN1bHRzLGRmKQp9CnJlc3VsdHMyPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6NCl7CiAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIn4vUHJvamVjdHMvU0xpTS9QYWNIZXJyaW5nL1dGX211dGF0aW9uIixpLCIudHh0IiksIHNraXA9MikKICAgICAgICBkZiRBRjwtZGYkVjkvMjAwCiAgICAgICAgZGYkdGltZTwtdGltZVtpXQogICAgICAgIHJlc3VsdHMyPC1yYmluZChyZXN1bHRzMixkZikKfQoKbWVhbjwtZGF0YS5mcmFtZShhZ2dyZWdhdGUocmVzdWx0cyRBRiwgYnk9bGlzdChyZXN1bHRzJHRpbWUpLCBGVU49bWVhbikpCm1lYW4yPC1kYXRhLmZyYW1lKGFnZ3JlZ2F0ZShyZXN1bHRzMiRBRiwgYnk9bGlzdChyZXN1bHRzMiR0aW1lKSwgRlVOPW1lYW4pKQpjb2xuYW1lcyhtZWFuKTwtYygiVGltZSIsIkFGIikKY29sbmFtZXMobWVhbjIpPC1jKCJUaW1lIiwiQUYiKQptZWFuJE1vZGVsPC0ibm9uV0YiCm1lYW4yJE1vZGVsPC0iV0YiClJlPC1yYmluZChtZWFuLCBtZWFuMikKCmdncGxvdChSZSwgYWVzKHg9VGltZSwgeT1BRiwgY29sb3I9TW9kZWwpKSsKICAgIGdlb21fcG9pbnQoKSt0aGVtZV9saWdodCgpK3lsaW0oMC4wMDYsMC4wMikrCiAgICBnZW9tX2xpbmUoYWVzKHg9VGltZSwgeT1BRiwgZ3JvdXA9TW9kZWwpKQpnZ3NhdmUoIi4uL091dHB1dC9DT1YvU2ltL21lYW5BRi5XRi52cy5ub25XRi5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMsIGRwaT0zMDApICAKYGBgICAgIAohW10oLi4vT3V0cHV0L0NPVi9TaW0vbWVhbkFGLldGLnZzLm5vbldGLnBuZykgICAKCgojIFRlbXBvcmFsIENvdmFyaWFuY2UgQW5hbHlzaXMKCiMjIERhdGEgcHJvY2Vzc2luZzogU3Vic2FtcGxlZCBpbmRpdmlkdWFscwoxLiBDcmVhdGUgc2FtcGxlIG5hbWVzIGZpbGVzIGZvciB0aGUgZ2VuZXJhdGVkIFZDRiBmaWxlcyAgCgpgYGAge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0gICAKIzEuIEZpeGVkIG51bWJlciBvZiBpbmRpdmlkdWFscwoKI1NlbGVjdCB0aGUgbnVtYmVyIG9mIHRpbWUgcG9pbnRzIGFuZCBudW1iZXIgb2Ygc2FtcGxlcyAoaW5kaXZpZHVhbHMpCnQ9MTAKbj0xMDAKCiNDcmVhdGUgYSBuYW1lIGZpbGUgdG8gcmVuYW1lIHRoZSBzYW1wbGVzIGluIHZjZgpmb3IgKGkgaW4gMTp0KXsKICAgIGRmPC1kYXRhLmZyYW1lKHNhbXBsZT1wYXN0ZTAoInRpbWUiLGktMSwiLiIsMTpuKSkKICAgIHdyaXRlLnRhYmxlKGRmLCBwYXN0ZTAoIn4vUHJvamVjdHMvU0xpTS9QYWNIZXJyaW5nL25ld3NhbXBsZWlkcy4iLGktMSwiLnR4dCIpLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLCBxdW90ZSA9IEYpCn0KCgojMi4gdGhlIEVudGlyZSBwb3B1bGF0aW9uCiNudW1iZXIgb2YgdGltZSBwZXJpb2QKdD0xMApsb2c8LXJlYWQuY3N2KCJ+L1Byb2plY3RzL1NMaU0vUGFjSGVycmluZy9ub25XRl9uZXV0cmFsX2xvZzIudHh0IikKdGltZXM8LXNlcSgxMDAwLCAxMDAwKzEwKih0LTEpLCAxMCkgCiNDcmVhdGUgYSBuYW1lIGZpbGUgdG8gcmVuYW1lIHRoZSBzYW1wbGVzIGluIHZjZgpmb3IgKGkgaW4gMTp0KXsKICAgIG48LWxvZyRudW1faW5kaXZpZHVhbHNbbG9nJGdlbmVyYXRpb249PXRpbWVzW2ldXQogICAgZGY8LWRhdGEuZnJhbWUoc2FtcGxlPXBhc3RlMCgidGltZSIsaS0xLCIuIiwxOm4pKQogICAgd3JpdGUudGFibGUoZGYsIHBhc3RlMCgifi9Qcm9qZWN0cy9TTGlNL1BhY0hlcnJpbmcvbmV3c2FtcGxlaWRzLiIsaS0xLCIudHh0IiksIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYsIHF1b3RlID0gRikKfQoKCmBgYAoKCjIuIENyZWF0ZSBhIGJhc2ggc2NyaXB0IHRvIHByb2Nlc3MgU2xpbSBWQ0YgZmlsZXMgCgpgYGAge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0gICAgCiNDcmVhdGUgdGhlIGJhc2ggc2NyaXB0IHRvIHJlZm9ybWF0IHRoZSBvdXRwdXQgb2Ygc2xpbQojc2VsZWN0IHRoZSBhcHByb3ByaWF0ZSBuYW1lCnJ1bjwtIm5vbldGLksxMDAwMC5zdWIxMDAiICAjc2VsZWN0IGEgbmFtZQptb2RlbDwtIm5vbldGIgpydW48LSJXRi5OMTAwMDAuc3ViMTAwIiAgI3NlbGVjdCBhIG5hbWUKbW9kZWw8LSJXRiIKcnVuPC0iV0YuTjEwMDAuc3ViMTAwLlBvczAuMi5nNTAwMCIgCgp0PC0xMAphbGw8LScnICMgKCdhbGwnIG9yICcnIG5vbmUpCgojIDEuIENyZWF0ZSBhIGJhc2ggc2NyaXB0CnNpbmsocGFzdGUwKCJ+L1Byb2plY3RzL1NMaU0vUGFjSGVycmluZy9zbGltXyIscnVuLCIuc2giKSkKY2F0KCIjIS9iaW4vYmFzaCBcblxuIikKY2F0KHBhc3RlMCgibWtkaXIgIiwgcnVuLCAiIFxuIikpCiNyZW5hbWUgdGhlIHNhbXBsZXMKZm9yIChpIGluIDE6dCl7CiAgICBjYXQocGFzdGUwKCJiY2Z0b29scyByZWhlYWRlciAiLG1vZGVsLGFsbCwiX3RpbWUiLGktMSwiLnZjZiAtcyBuZXdzYW1wbGVpZHMuIixpLTEsIi50eHQgLW8gIixydW4sIi8iLG1vZGVsLCJfdGltZSIsaS0xLCIudmNmIFxuIikpCn0KCmNhdChwYXN0ZTAoImNkICIscnVuLCIgXG4iKSkKY2F0KCJmb3IgZiBpbiAqLnZjZjsgZG8gZmlsZW5hbWU9JChiYXNlbmFtZSAkZik7IGJnemlwICRmIDsgZG9uZSBcbiIpCmNhdCgiZm9yIGYgaW4gKi52Y2YuZ3o7IGRvIGZpbGVuYW1lPSQoYmFzZW5hbWUgJGYpOyBiY2Z0b29scyBpbmRleCAkZiA7IGRvbmUgXG4iKQojZmluZCBpbnRlcnNlY3RpbmcgbG9jaQpjYXQocGFzdGUwKCJiY2Z0b29scyBpc2VjIC1uPSIsdCwiIC1wIGlzZWMgLS10aHJlYWRzIDEwICp2Y2YuZ3ogXG4iKSkKY2F0KHBhc3RlMCgiYmNmdG9vbHMgbWVyZ2UgKnZjZi5neiAtbyAiLG1vZGVsLCJfY29tYmluZWQudmNmLmd6IFxuIikpCmNhdChwYXN0ZTAoImJjZnRvb2xzIGluZGV4ICIsbW9kZWwsIl9jb21iaW5lZC52Y2YuZ3ogXG4iKSkKIyBleHRyYWN0IGludGVyc2VjIGxvY2kgZnJvbSB0aGUgY29tYmluZWQgCmNhdChwYXN0ZTAoImJjZnRvb2xzIHZpZXcgLVIgaXNlYy9zaXRlcy50eHQgIixtb2RlbCwiX2NvbWJpbmVkLnZjZi5neiAtT3ogPiAiLG1vZGVsLCJfaXNlYy52Y2YuZ3ogXG4iKSkKY2F0KHBhc3RlMCgicm0gaXNlYy8qLnZjZiIpKQpzaW5rKE5VTEwpCgojIyBSdW4gIGJhc2ggc2xpbV94eHh4LnNoCmBgYAoKIyBSZXN1bHRzIGZyb20gdGVtcG9yYWwgY292YXJpYW5jZSBhbmFseXNpcwoqIE5lZWQgdG8gcmFuZG9tbHkgcGVybXV0ZSB0aGUgdHJhY2tlZCBhbGxlbGUgKGRyYXcgYSBCZXJub3VsbGkgcmFuZG9tIHZhcmlhYmxlIGFuZCBpZiBpdCdzIDEgeW91IHJhbmRvbWx5IGZsaXAgdGhlIGZyZXF1ZW5jeSkgdG8gYXZvaWQgYmlhcyAKCkZ1bmN0aW9ucyB0byBjcmVhdGUgY292YXJpYW5jZSBzdW1tYXJ5IHBsb3RzICAKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0gCiMgZnVuY3Rpb24gdG8gcmVhZCB0aGUgY292YXJpYW5jZSBvdXRwdXQgZmlsZSBmb3JtIGN2dGtweSB3aXRoIDQgdGltZSBwb2ludHMsIHNpbXVsYXRpb24gcHdzIHBvcHMKIyBmbmFtZT1maWxlIG5hbWUsIG1vZGVsPSAiV0YiIG9yICJub25XRiIsIHQ9IyBvZiB0aW1lIHBvaW50cykKcmVxdWlyZSgic3RyaW5nciIpCmNvdlJlc3VsdHM8LWZ1bmN0aW9uKGZuYW1lLCBtb2RlbCwgdCl7CiAgICBjb3Y8LXJlYWQuY3N2KHBhc3RlMCgifi9Qcm9qZWN0cy9QYWNoZXJyaW5nX1ZpbmNlbnQvc2xpbS8iLGZuYW1lKSkKICAgIGNvdjwtY292WywtMV0KICAgICNyZXNoYXBlIHRoZSBtYXRyaXgKICAgIG1hdDE8LWNvdlsxOih0LTEpLF0KICAgIG1hdDI8LWNvdlt0OigyKnQtMiksXQogICAgCiAgICBjb3ZkZjwtZGF0YS5mcmFtZSgpCiAgICBrPTEKICAgIGZvciAoaSBpbiAxOm5yb3cobWF0MSkpewogICAgICAgIGZvciAoaiBpbiAxOm5jb2wobWF0MSkpewogICAgICAgICBjb3ZkZltrLDFdPC1tYXQyW2ksal0KICAgICAgICAgY292ZGZbaywyXTwtbWF0MVtpLGpdCiAgICAgICAgIGs9aysxCiAgICAgICAgfQogICAgfQogICAgY29sbmFtZXMoY292ZGYpPC1jKCJsYWJlbCIsInZhbHVlIikKICAgIGNvdmRmJHZhbHVlPC1hcy5udW1lcmljKGNvdmRmJHZhbHVlKQogICAgY292YXI8LWNvdmRmW2dyZXAoImNvdiIsY292ZGYkbGFiZWwpLF0KICAgICAgICAgICAgCiAgICAjcmVtb3ZlIHRoZSByZWR1bmRhbnQgdmFsdWVzCiAgICBpZHM8LXN0cl9tYXRjaChjb3ZhciRsYWJlbCwgInNpbTpcXHMoLio/KVxcLFxcc3NpbTpcXHMoLio/KVxcKSIpCiAgICBpZHM8LWlkc1ssMjozXQogICAgcmVtb3ZlPC1kdXBsaWNhdGVkKGxhcHBseSgxOm5yb3coaWRzKSwgZnVuY3Rpb24oeCkgewogICAgICAgIEE8LWlkc1t4LF0KICAgICAgICBBW29yZGVyKEEpXQogICAgfSAgKSkKICAgIGNvdmFyPC1jb3ZhclshcmVtb3ZlLF0gCiAgICAKICAgICNhc3NpZ24gdGhlIHN0YXJ0aW5nIHRpbWUgcGVyaW9kIGFuZCBjb3ZlcmluZyBwZXJpb2QgdmFsdWVzCiAgICB2ZWNuPC0xOih0LTIpCiAgICBzeXI8LWMoKQogICAgZm9yIChpIGluIDE6bGVuZ3RoKHZlY24pKXsKICAgICAgICBzeXI8LWMoc3lyLCByZXAoaSwgdGltZXM9KHQtaS0xKSkpCiAgICB9CiAgICBjb3ZhciRzdGFydF95ZWFyPC1zeXIKICAgIAogICAgZXlyPC1jKCkKICAgIGZvciAoaSBpbiAxOih0LTIpKXsKICAgICAgICB2PC0oaSsxKToodC0xKQogICAgICAgIGV5cjwtYyhleXIsdikKICAgIH0KICAgIGNvdmFyJGVuZF95ZWFyPC1leXIKCiAgICBuZXdmaWxlPC1nc3ViKCIuY3N2IiwiIiwgZm5hbWUpCiAgICBuZXdmaWxlPC1nc3ViKCJfdGVtcF9jb3ZfbWF0cml4IiwiIiwgbmV3ZmlsZSkKICAgIGdncGxvdChkYXRhPWNvdmFyLCBhZXMoeD1lbmRfeWVhciwgeT12YWx1ZSxncm91cD1zdGFydF95ZWFyLCBjb2xvcj1mYWN0b3Ioc3RhcnRfeWVhcikpKSsKICAgICAgICBnZW9tX3BvaW50KHNpemU9MykrCiAgICAgICAgZ2VvbV9saW5lKCkrCiAgICAgICAgeWxhYigiQ292YXJpYW5jZSIpK3hsYWIoJycpK3RoZW1lX2NsYXNzaWMoKSsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSxsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsY29sb3I9ImdyYXk3MCIsIHNpemU9MC4zKStnZ3RpdGxlKHBhc3RlMChtb2RlbCkpKwogICAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hLCBsaW1pdHMgPSBjKC0wLjAwMSwwLjAwMSkpCiAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvQ09WL1NpbS8iLCBuZXdmaWxlLCAiX25ldXRyYWwucG5nIiksd2lkdGggPSA2LCBoZWlnaHQgPSAzLCBkcGk9MzAwKQogICAgcHJpbnQocGFzdGUwKCIuLi9PdXRwdXQvQ09WL1NpbS8iLCBuZXdmaWxlLCAiX25ldXRyYWwucG5nIikpCn0KCiNObyB5bGltCmNvdlJlc3VsdHMyPC1mdW5jdGlvbihmbmFtZSwgbW9kZWwsIHQpewogICAgY292PC1yZWFkLmNzdihwYXN0ZTAoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L3NsaW0vIixmbmFtZSkpCiAgICBjb3Y8LWNvdlssLTFdCiAgICAjcmVzaGFwZSB0aGUgbWF0cml4CiAgICBtYXQxPC1jb3ZbMToodC0xKSxdCiAgICBtYXQyPC1jb3ZbdDooMip0LTIpLF0KICAgIAogICAgY292ZGY8LWRhdGEuZnJhbWUoKQogICAgaz0xCiAgICBmb3IgKGkgaW4gMTpucm93KG1hdDEpKXsKICAgICAgICBmb3IgKGogaW4gMTpuY29sKG1hdDEpKXsKICAgICAgICAgY292ZGZbaywxXTwtbWF0MltpLGpdCiAgICAgICAgIGNvdmRmW2ssMl08LW1hdDFbaSxqXQogICAgICAgICBrPWsrMQogICAgICAgIH0KICAgIH0KICAgIGNvbG5hbWVzKGNvdmRmKTwtYygibGFiZWwiLCJ2YWx1ZSIpCiAgICBjb3ZkZiR2YWx1ZTwtYXMubnVtZXJpYyhjb3ZkZiR2YWx1ZSkKICAgIGNvdmFyPC1jb3ZkZltncmVwKCJjb3YiLGNvdmRmJGxhYmVsKSxdCiAgICAgICAgICAgIAogICAgI3JlbW92ZSB0aGUgcmVkdW5kYW50IHZhbHVlcwogICAgaWRzPC1zdHJfbWF0Y2goY292YXIkbGFiZWwsICJzaW06XFxzKC4qPylcXCxcXHNzaW06XFxzKC4qPylcXCkiKQogICAgaWRzPC1pZHNbLDI6M10KICAgIHJlbW92ZTwtZHVwbGljYXRlZChsYXBwbHkoMTpucm93KGlkcyksIGZ1bmN0aW9uKHgpIHsKICAgICAgICBBPC1pZHNbeCxdCiAgICAgICAgQVtvcmRlcihBKV0KICAgIH0gICkpCiAgICBjb3ZhcjwtY292YXJbIXJlbW92ZSxdIAogICAgCiAgICAjYXNzaWduIHRoZSBzdGFydGluZyB0aW1lIHBlcmlvZCBhbmQgY292ZXJpbmcgcGVyaW9kIHZhbHVlcwogICAgdmVjbjwtMToodC0yKQogICAgc3lyPC1jKCkKICAgIGZvciAoaSBpbiAxOmxlbmd0aCh2ZWNuKSl7CiAgICAgICAgc3lyPC1jKHN5ciwgcmVwKGksIHRpbWVzPSh0LWktMSkpKQogICAgfQogICAgY292YXIkc3RhcnRfeWVhcjwtc3lyCiAgICAKICAgIGV5cjwtYygpCiAgICBmb3IgKGkgaW4gMToodC0yKSl7CiAgICAgICAgdjwtKGkrMSk6KHQtMSkKICAgICAgICBleXI8LWMoZXlyLHYpCiAgICB9CiAgICBjb3ZhciRlbmRfeWVhcjwtZXlyCgogICAgbmV3ZmlsZTwtZ3N1YigiLmNzdiIsIiIsIGZuYW1lKQogICAgbmV3ZmlsZTwtZ3N1YigiX3RlbXBfY292X21hdHJpeCIsIiIsIG5ld2ZpbGUpCiAgICBnZ3Bsb3QoZGF0YT1jb3ZhciwgYWVzKHg9ZW5kX3llYXIsIHk9dmFsdWUsZ3JvdXA9c3RhcnRfeWVhciwgY29sb3I9ZmFjdG9yKHN0YXJ0X3llYXIpKSkrCiAgICAgICAgZ2VvbV9wb2ludChzaXplPTMpKwogICAgICAgIGdlb21fbGluZSgpKwogICAgICAgIHlsYWIoIkNvdmFyaWFuY2UiKSt4bGFiKCcnKSt0aGVtZV9jbGFzc2ljKCkrCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLGNvbG9yPSJncmF5NzAiLCBzaXplPTAuMykrZ2d0aXRsZShwYXN0ZTAobW9kZWwpKSsKICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkKICAgIGdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9DT1YvU2ltLyIsIG5ld2ZpbGUsICJfbmV1dHJhbF9ub3lsaW0ucG5nIiksd2lkdGggPSA2LCBoZWlnaHQgPSAzLCBkcGk9MzAwKQogICAgcHJpbnQocGFzdGUwKCIuLi9PdXRwdXQvQ09WL1NpbS8iLCBuZXdmaWxlLCAiX25ldXRyYWxfbm95bGltLnBuZyIpKQp9CmBgYAoKIyMgVXNlIHRoZSBlbnRpcmUgcG9wdWxhdGlvbiB0byBjYWxjdWxhdGUgQ09WIGFuZCBBRiAobm8gc3Vic2FtcGxpbmcgb2YgaW5kaXZpZHVhbHMpCgojIyMgV0YgbmV1dHJhbCAoYWxsIGluZGl2aWR1YWxzLCAxMCAgdGltZXBvaW50cykKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9IApjb3ZSZXN1bHRzKCJTbGltX1dGX04xMDAwX25vQ25vU190ZW1wX2Nvdl9tYXRyaXhfMjUwa3dpbi5jc3YiLCAiV0YgbmV1dHJhbCBhbGwgKE49MTAwMCkiLCAxMCkKYGBgCiFbV0ZdKC4uL091dHB1dC9DT1YvU2ltL1NsaW1fV0ZfTjEwMDBfbm9Dbm9TXzI1MGt3aW5fbmV1dHJhbC5wbmcpe3dpZHRoPTcwJX0KCiMjIyBXRiB3aXRoIG5vbldGIG1vZGVsLCBuZXV0cmFsIChhbGwgaW5kaXZpZHVhbHMsIDEwICB0aW1lcG9pbnRzKQoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0gCmNvdlJlc3VsdHMoIlNsaW1fV0Zub253Zl9LMTAwMF9ub0Nub1NfdGVtcF9jb3ZfbWF0cml4XzI1MGt3aW4uY3N2IiwgIldGbm9ud2YgbmV1dHJhbCBhbGwgKEs9MTAwMCkiLCAxMCkKCmBgYAohW1dGXSguLi9PdXRwdXQvQ09WL1NpbS9TbGltX1dGbm9ud2ZfSzEwMDBfbm9Dbm9TXzI1MGt3aW5fbmV1dHJhbC5wbmcpe3dpZHRoPTcwJX0KCiMjIyBub25XRiBuZXV0cmFsIChLPTEwMDAsIGFsbCBpbmRpdmlkdWFscywgMTAgIHRpbWVwb2ludHMpCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfSAKI2NvdlJlc3VsdHMoIlNsaW1fbm9uV0ZfYWxsX0sxMDAwX3QxMF90ZW1wX2Nvdl9tYXRyaXhfMjUwa3dpbi5jc3YiLCAibm9uV0YgbmV1dHJhbCBhbGwgKEs9MTAwMCkiLCAxMCkKY292UmVzdWx0cygiU2xpbV9ub25XRl9LMTAwMF9ub0Nub1NfdGVtcF9jb3ZfbWF0cml4XzI1MGt3aW4uY3N2IiwgIm5vbldGIG5ldXRyYWwgYWxsIChLPTEwMDAsIG5vQ25vUykiLCAxMCkKCmBgYAohW10oLi4vT3V0cHV0L0NPVi9TaW0vU2xpbV9ub25XRl9LMTAwMF9ub0Nub1NfMjUwa3dpbl9uZXV0cmFsLnBuZyl7d2lkdGg9NzAlfQpgYGB7cn0KY292UmVzdWx0cygiU2xpbV9ub25XRl9LMTAwMF93Q3dTX3RlbXBfY292X21hdHJpeF8yNTBrd2luLmNzdiIsICJub25XRiBuZXV0cmFsIGFsbCAoSz0xMDAwKSIsIDEwKQoKYGBgCgoKIVtdKC4uL091dHB1dC9DT1YvU2ltL1NsaW1fbm9uV0ZfYWxsX0sxMDAwX3QxMF8yNTBrd2luX25ldXRyYWwucG5nKXt3aWR0aD03MCV9CgoKIyMgU3Vic2FtcGxpbmcgMTAwIGluZGl2aWR1YWxzIGZyb20gYSBwb3B1bGF0aW9uIChOPTEwMDApOiBubyBjb3JyZWN0aW9uCgojIyMgV0YgKE49MTAwMCwgc3ViMTAwKSAgLW5vIGJpYXMgY29ycmVjdGlvbiBhcHBsaWVkCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfSAKY292UmVzdWx0czIoIlNsaW1fV0ZfTjEwMDBfc3ViMTAwLnYyX25vQ25vU190ZW1wX2Nvdl9tYXRyaXhfMjUwa3dpbi5jc3YiLCAiV0YgbmV1dHJhbCAoc2FtcGxlZCAxMDAsIG5vIGNvcnJlY3Rpb24pIiwgMTApCgpgYGAKIVtdKC4uL091dHB1dC9DT1YvU2ltL1NsaW1fV0ZfTjEwMDBfc3ViMTAwLnYyX25vQ25vU18yNTBrd2luX25ldXRyYWxfbm95bGltLnBuZyl7d2lkdGg9NDAlfQoKKiBTZXQgWS1heGlzIHRvIC0wLjAwMSAtIDAuMDAxOgoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KY292UmVzdWx0cygiU2xpbV9XRl9OMTAwMF9zdWIxMDAudjJfbm9Dbm9TX3RlbXBfY292X21hdHJpeF8yNTBrd2luLmNzdiIsICJXRiBuZXV0cmFsIChzYW1wbGVkIDEwMCwgbm8gY29ycmVjdGlvbikiLCAxMCkKYGBgCiFbXSguLi9PdXRwdXQvQ09WL1NpbS9TbGltX1dGX04xMDAwX3N1YjEwMC52Ml9ub0Nub1NfMjUwa3dpbl9uZXV0cmFsLnBuZyl7d2lkdGg9NzAlfQoKCgojIyMgV0YgKE49MTAwMCwgc3ViMTAwKSAgd2l0aCBiaWFzIGNvcnJlY3Rpb24gYXBwbGllZAoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KY292UmVzdWx0czIoIlNsaW1fV0ZfTjEwMDBfc3ViMTAwLnYyX3dDd1NfdGVtcF9jb3ZfbWF0cml4XzI1MGt3aW4uY3N2IiwgIldGIG5ldXRyYWwgdjIgKE49MTAwMCxzdWI9MTAwKSIsIDEwKQpgYGAKIVtdKC4uL091dHB1dC9DT1YvU2ltL1NsaW1fV0ZfTjEwMDBfc3ViMTAwLnYyX3dDd1NfMjUwa3dpbl9uZXV0cmFsLnBuZyl7d2lkdGg9NzAlfQoKIyMjIFdGIHdpdGggbm9uV0YgbW9kZWwgKEs9MTAwMCwgc3ViPTEwMCkgLW5vIGJpYXMgY29ycmVjdGlvbgoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KY292UmVzdWx0cygiU2xpbV9XRm5vbndmX0sxMDAwX3N1YjEwMF9ub0Nub1NfdGVtcF9jb3ZfbWF0cml4XzI1MGt3aW4uY3N2IiwgIldGbm9ud2YgbmV1dHJhbCAoSz0xMDAwLCBzdWI9MTAwKSwgbm8gY29ycmVjdGlvbiIsIDEwKQpgYGAKIVtdKC4uL091dHB1dC9DT1YvU2ltL1NsaW1fV0Zub253Zl9LMTAwMF9zdWIxMDBfbm9Dbm9TXzI1MGt3aW5fbmV1dHJhbC5wbmcpe3dpZHRoPTcwJX0KCiMjIyBXRiB3aXRoIG5vbldGIG1vZGVsIChLPTEwMDAsIHN1Yj0xMDApIC13aXRoIGJpYXMgY29ycmVjdGlvbgoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KY292UmVzdWx0czIoIlNsaW1fV0Zub253Zl9LMTAwMF9zdWIxMDBfd0N3U190ZW1wX2Nvdl9tYXRyaXhfMjUwa3dpbi5jc3YiLCAiV0Zub253ZiBuZXV0cmFsIChLPTEwMDAsIHN1Yj0xMDApLCBubyBjb3JyZWN0aW9uIiwgMTApCmBgYAohW10oLi4vT3V0cHV0L0NPVi9TaW0vU2xpbV9XRm5vbndmX0sxMDAwX3N1YjEwMF93Q3dTXzI1MGt3aW5fbmV1dHJhbF9ub3lsaW0ucG5nKXt3aWR0aD03MCV9IAoKCiMjIyBub25XRiBtb2RlbCAoSz0xMDAwLCBzdWI9MTAwKSAtbm8gYmlhcyBjb3JyZWN0aW9uCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpjb3ZSZXN1bHRzKCJTbGltX25vbldGX0sxMDAwX3N1YjEwMF9ub0Nub1NfdGVtcF9jb3ZfbWF0cml4XzI1MGt3aW4uY3N2IiwgIldGbm9ud2YgbmV1dHJhbCAoSz0xMDAwLCBzdWI9MTAwKSwgbm8gY29ycmVjdGlvbiIsIDEwKQpgYGAKIVtdKC4uL091dHB1dC9DT1YvU2ltL1NsaW1fbm9uV0ZfSzEwMDBfc3ViMTAwX25vQ25vU18yNTBrd2luX25ldXRyYWwucG5nKXt3aWR0aD03MCV9CgojIyMgbm9uV0YgbW9kZWwgKEs9MTAwMCwgc3ViPTEwMCkgLXdpdGggYmlhcyBjb3JyZWN0aW9uCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpjb3ZSZXN1bHRzMigiU2xpbV9ub25XRl9LMTAwMF9zdWIxMDBfd0N3U190ZW1wX2Nvdl9tYXRyaXhfMjUwa3dpbi5jc3YiLCAiV0Zub253ZiBuZXV0cmFsIChLPTEwMDAsIHN1Yj0xMDApLCB3aXRoIGNvcnJlY3Rpb24iLCAxMCkKYGBgCiFbXSguLi9PdXRwdXQvQ09WL1NpbS9TbGltX1dGbm9ud2ZfSzEwMDBfc3ViMTAwX3dDd1NfMjUwa3dpbl9uZXV0cmFsX25veWxpbS5wbmcpe3dpZHRoPTcwJX0KCgoKCgoKIyMjIFdGIE49MTAwIGVudGlyZSBwb3B1bGF0aW9uICAKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0UsIGVjaG89VFJVRX0KI2xpc3QgZmlsZSBuYW1lcyBmcm9tIHRlbXAgY292IGFuYWx5c2lzCiNjb3ZmaWxlczwtbGlzdC5maWxlcygifi9Qcm9qZWN0cy9QYWNoZXJyaW5nX1ZpbmNlbnQvc2xpbS8iLCBwYXR0ZXJuPSJTbGltXyIpCgpjb3ZSZXN1bHRzMigiU2xpbV9XRl9OMTAwX25vQ25vU190ZW1wX2Nvdl9tYXRyaXhfMjUwa3dpbi5jc3YiLCAiV0YgbmV1dHJhbCBhbGwgKE49MTAwKSIsIDEwKQpgYGAKIVtXRl0oLi4vT3V0cHV0L0NPVi9TaW0vU2xpbV9XRl9OMTAwX25vQ25vU18yNTBrd2luX25ldXRyYWxfbm95bGltLnBuZyl7d2lkdGg9NzAlfQoKIyMgU2FtcGxlIDEwMDAgaW5kaXZpZHVhbHMgZnJvbSBOPTEwMDAwIHBvcHVsYXRpb24gIAoKIyMjIFdGIG5ldXRyYWwgTj0xMDAwMCwgc3ViPTEwMDAgKG5vIGJpYXMgY29ycmVjdGlvbiwgbm8gc3RhbmRhcmRpemF0aW9uKQoKYGBge3J9CiNjb3ZSZXN1bHRzMigiU2xpbV9XRl9OMTAwMDBfc3ViMTAwMF9ub0Nub1NfdGVtcF9jb3ZfbWF0cml4XzI1MGt3aW4uY3N2IiwgIldGIG5ldXRyYWwgKE49MTAwMDAsIHN1Yj0xMDAwLCAjbm9DLCBub1MpIiwgMTApCmNvdlJlc3VsdHMoIlNsaW1fV0ZfTjEwMDAwX3N1YjEwMDBfbm9Dbm9TX3RlbXBfY292X21hdHJpeF8yNTBrd2luLmNzdiIsICJXRiBuZXV0cmFsIChOPTEwMDAwLCBzdWI9MTAwMCkiLCAxMCkKYGBgCgohW10oLi4vT3V0cHV0L0NPVi9TaW0vU2xpbV9XRl9OMTAwMDBfc3ViMTAwMF9ub0Nub1NfMjUwa3dpbl9uZXV0cmFsLnBuZyl7d2lkdGg9NzAlfQoKIyMjIFdGIG5ldXRyYWwgTj0xMDAwMCwgc3ViPTEwMDAgd2l0aCBiaWFzIGNvcnJlY3Rpb24KCmBgYHtyfQpjb3ZSZXN1bHRzMigiU2xpbV9XRl9OMTAwMDBfc3ViMTAwMF93Q3dTX3RlbXBfY292X21hdHJpeF8yNTBrd2luLmNzdiIsICJXRiBuZXV0cmFsKE49MTAwMDAsIHN1Yj0xMDAwKSB3LyBjb3JyZWN0aW9uIiwgMTApCmBgYAohW10oLi4vT3V0cHV0L0NPVi9TaW0vU2xpbV9XRl9OMTAwMDBfc3ViMTAwMF93Q3dTXzI1MGt3aW5fbmV1dHJhbF9ub3lsaW0ucG5nKXt3aWR0aD03MCV9CgoKIyMjIFdGIG5ldXRyYWwgTj0xMDAwMCwgc3ViPTEwMDAgKG5vIGJpYXMgY29ycmVjdGlvbiwgd2l0aCBzdGFuZGFyZGl6YXRpb24pCgpgYGB7cn0KY292UmVzdWx0cygiU2xpbV9XRl9OMTAwMDBfc3ViMTAwMF9ub0N3U190ZW1wX2Nvdl9tYXRyaXhfMjUwa3dpbi5jc3YiLCAiV0YgbmV1dHJhbCBhbGwgKE49MTAwMDAsIHN1Yj0xMDAwKSBub0N3UyIsIDEwKQoKYGBgCgohW10oLi4vT3V0cHV0L0NPVi9TaW0vU2xpbV9XRl9OMTAwMDBfc3ViMTAwMF9ub0N3U18yNTBrd2luX25ldXRyYWwucG5nKSB7d2lkdGg9NzAlfQoKYGBge3J9CmNvdlJlc3VsdHMoIlNsaW1fV0ZfTjEwMDAwX3MxMDBfbm9Dd1NfdGVtcF9jb3ZfbWF0cml4XzI1MGt3aW4uY3N2IiwgIldGIG5ldXRyYWwgKE49MTAwMDAsIHN1Yj0xMDApIG5vQ3dTIiwgMTApCgpgYGAKCiFbXSguLi9PdXRwdXQvQ09WL1NpbS9TbGltX1dGX04xMDAwMF9zMTAwX25vQ3dTXzI1MGt3aW5fbmV1dHJhbC5wbmcpCmBgYHtyfQpjb3ZSZXN1bHRzKCJTbGltX25vbldGX0sxMDAwMF9zMTAwX25vQ25vU190ZW1wX2Nvdl9tYXRyaXhfMjUwa3dpbi5jc3YiLCAibm9uV0YgbmV1dHJhbCAoSz0xMDAwMCwgc3ViPTEwMCkgbm9Dbm9TIiwgMTApCgpgYGAKCiFbXSguLi9PdXRwdXQvQ09WL1NpbS9TbGltX25vbldGX0sxMDAwMF9zMTAwX25vQ25vU18yNTBrd2luX25ldXRyYWwucG5nKQoKIyMjIEFkZGluZyBiZW5lZmljaWFsIG11dGFpdG9uCgpgYGB7cn0KY292UmVzdWx0cygiU2xpbV9XRl9OMTAwMF9zMTAwX25vQ25vU19Qb3MwLjFfdGVtcF9jb3ZfbWF0cml4XzI1MGt3aW4uY3N2IiwgIldGIHdpdGggUG9zaXRpdmUgbXV0cygwLjEpIChOPTEwMDAsIHN1Yj0xMDApIG5vQ25vUyIsIDEwKQpjb3ZSZXN1bHRzKCJTbGltX1dGX04xMDAwX3MxMDBfbm9Dd1NfUG9zMC4xX3RlbXBfY292X21hdHJpeF8yNTBrd2luLmNzdiIsICJXRiB3aXRoIFBvc2l0aXZlIG11dHMoMC4xKSAoTj0xMDAwLCBzdWI9MTAwKSBub0N3UyIsIDEwKQoKYGBgCiFbXSguLi9PdXRwdXQvQ09WL1NpbS9TbGltX1dGX04xMDAwX3MxMDBfbm9Dbm9TX1BvczAuMV8yNTBrd2luX25ldXRyYWwucG5nKQohW10oLi4vT3V0cHV0L0NPVi9TaW0vU2xpbV9XRl9OMTAwMF9zMTAwX25vQ3dTX1BvczAuMV8yNTBrd2luX25ldXRyYWwucG5nKQoKCgoKYGBge3J9CmNvdlJlc3VsdHMoIlNsaW1fV0ZfTjEwMDBfczEwMF9ub0N3U19Qb3MwLjJfZzUwMDBfdGVtcF9jb3ZfbWF0cml4XzI1MGt3aW4uY3N2IiwgIldGIHdpdGggUG9zaXRpdmUoMC4yKSAoTj0xMDAwLCBzdWI9MTAwKSBub0N3UyIsIDEwKQoKYGBgCiFbXSguLi9PdXRwdXQvQ09WL1NpbS9TbGltX1dGX04xMDAwX3MxMDBfbm9Dd1NfUG9zMC4yX2c1MDAwXzI1MGt3aW5fbmV1dHJhbC5wbmcpCgoKCiFbXSguLi9PdXRwdXQvQ09WL1NpbS9TbGltX1dGX04xMDAwX3MxMDBfbm9Dbm9TX1BvczAuNV8yNTBrd2luX25ldXRyYWwucG5nKSAKCiFbXSguLi9PdXRwdXQvQ09WL1NpbS9TbGltX1dGX04xMDAwX3MxMDBfbm9Dd1NfUG9zMC4xXzI1MGt3aW5fbmV1dHJhbC5wbmcpCgpgYGB7cn0KY292UmVzdWx0cygiU2xpbV9XRl9OMTAwMF9zMTAwX3dDbm9TX1BvczAuMl9nNTAwMF90ZW1wX2Nvdl9tYXRyaXhfMjUwa3dpbi5jc3YiLCAiV0Ygd2l0aCBQb3NpdGl2ZSgwLjIpIChOPTEwMDAsIHN1Yj0xMDApIG5vQ25vUyIsIDEwKQoKYGBgCiFbXSguLi9PdXRwdXQvQ09WL1NpbS9TbGltX1dGX04xMDAwX3MxMDBfd0Nub1NfUG9zMC4yX2c1MDAwXzI1MGt3aW5fbmV1dHJhbC5wbmcpCgohW10oLi4vT3V0cHV0L0NPVi9TaW0vU2xpbV9XRl9OMTAwMF9zMTAwX3dDd1NfUG9zMC4yX2c1MDAwXzI1MGt3aW5fbmV1dHJhbC5wbmcpCgpgYGB7cn0KY292UmVzdWx0cygiU2xpbV9XRl9OMTAwMF9zMTAwX3dDbm9TX1BvczAuMl9nNTAwMF90ZW1wX2Nvdl9tYXRyaXhfMjUwa3dpbi5jc3YiLCAiV0Ygd2l0aCBQb3NpdGl2ZSgwLjIpIChOPTEwMDAsIHN1Yj0xMDApIG5vQ25vUyIsIDEwKQoKYGBgCgo8YnI+CgojIyBBY3R1YWwgZGF0YSBmb3IgMyBwb3B1bGF0aW9ucyAgCgohW10oLi4vT3V0cHV0L0NPVi9NRDcwMDBfQ292X292ZXJ0aW1lX0NJXzI1MGsud2luZG93X25ldy5wbmcpe3dpZHRoPTYwJX0KCiMgRXN0aWFtdGUgTmUgZnJvbSBzaW11bGF0aW9uIHJlc3VsdHMgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKcmVxdWlyZShkYXRhLnRhYmxlKQpyZXF1aXJlKGJvb3QpCnNvdXJjZSgiLi4vUnNjcmlwdHMvY2FsY05lLlIiKQoKI0FGIGRhdGEgKHVzaW5nIGZsaXAgZGF0YSkKd2Y8LWZyZWFkKCJ+L1Byb2plY3RzL3BhY2hlcnJpbmdfVmluY2VudC9zbGltL0FGX1dGX04xMDAwMF9zMTAwX2ZsaXAuY3N2IikKbm9ud2Y8LWZyZWFkKCJ+L1Byb2plY3RzL3BhY2hlcnJpbmdfVmluY2VudC9zbGltL0FGX25vbldGX0sxMDAwMF9zMTAwLmNzdiIpCnNldG5hbWVzKHdmLCBwYXN0ZTAoInRpbWUiLDA6OSkpCnNldG5hbWVzKG5vbndmLCBwYXN0ZTAoInRpbWUiLDA6OSkpCgpjb21iPC1kYXRhLmZyYW1lKHQxPXBhc3RlMCgidGltZSIsMDo4KSwgdDI9cGFzdGUwKCJ0aW1lIiwxOjkpKQoKCmRmIDwtIGRmMVtkZjIsIC4oY2hyb21vLCBwb3NpdGlvbiwgZnJlcTEsIGZyZXEyLCBuSW5kMSwgbkluZDIpXVshaXMubmEoZnJlcTEpICYgIWlzLm5hKGZyZXEyKSAmIGZyZXExID4gMC4xICYgZnJlcTIgPiAwLjEsIF0KICAgIGc9Z2Vuc1tpXQogICAgCiAgICBlc3ROZSROZVtpXTwtZGZbLCBqck5lMihmcmVxMSwgZnJlcTIsIG5JbmQxLCBuSW5kMiwgZyldIAoKZXN0TmU8LWRhdGEuZnJhbWUocG9wMT1jb21iWywxXSwgcG9wMj1jb21iWywyXSkKZ2VuczwtCgpmb3IgKGkgaW4gMTogbnJvdyhjb21iKSl7CiAgICBkZjE8LXdmWyxpOihpKzEpXQogICAgZGYxPC1hcHBseShkZjEsIDEsIGZ1bmN0aW9uKHgpIDEteCkKICAgIGRmMTwtZGF0YS50YWJsZSh0KGRmMSkpCiAgICAKICAgIGRmMjwtbm9ud2ZbLGk6KGkrMSldCiAgICAKICAgIHNldG5hbWVzKGRmMSwgMToyLCBjKCJmcmVxMSIsICJmcmVxMiIpKQogICAgc2V0bmFtZXMoZGYyLCAxOjIsIGMoImZyZXExIiwgImZyZXEyIikpCiAgICAKICAgIGRmMSRuSW5kMTwtMTAwCiAgICBkZjEkbkluZDI8LTEwMAogICAgZGYyJG5JbmQxPC0xMDAKICAgIGRmMiRuSW5kMjwtMTAwCiAgICAKICAgIGRmIDwtIGRmMVtmcmVxMSA+IDAuMSAmIGZyZXEyID4gMC4xLF0KICAgIGc9MTAKICAgIAogICAgZGZbLCBqck5lMihmcmVxMSwgZnJlcTIsIG5JbmQxLCBuSW5kMiwgZyldIAoKICAgIAogICAgCiAgICBlc3ROZSROZVtpXTwtZGZbLCBqck5lMihmcmVxMSwgZnJlcTIsIG5JbmQxLCBuSW5kMiwgZyldIAoKICAgICMgYmxvY2sgYm9vdHN0cmFwcGluZyBhY3Jvc3MgTEdzCiAgICB1cS5jaCA8LSBkZlssIHNvcnQodW5pcXVlKGNocm9tbykpXQoKICAgIGJvb3QucmUgPC0gYm9vdCh1cS5jaCwganJOZTJibG9jaywgMTAwMCwgZ2VuID0gZywgYWxsZGF0YSA9IGRmKQogICAgZXN0TmUkbWVkaWFuW2ldPC1tZWRpYW4oYm9vdC5yZSR0W2lzLmZpbml0ZShib290LnJlJHQpXSkgIyBtZWRpYW4gYm9vdHN0cmFwCiAgICBlc3ROZSRtZWFuW2ldPC1tZWFuKGJvb3QucmUkdFtpcy5maW5pdGUoYm9vdC5yZSR0KV0pCiAgICBjaTwtYm9vdC5jaShib290LnJlLCB0eXBlID0gYygncGVyYycpKQogICAgIzk1JSBDLkkuCiAgICBlc3ROZSRDSS5sb3dbaV08LWNpJHBlcmNlbnRbNF0KICAgIGVzdE5lJENJLnVwW2ldPC1jaSRwZXJjZW50WzVdCiAgICAKICAgICNyZXNldCB0aGUgYXR0aWJ1dGVzCiAgICBzZXRuYW1lcyhkZjEsIGMoImZyZXExIiwgJ25JbmQxJyksYygia25vd25FTSIsICduSW5kJykpCiAgICBzZXRuYW1lcyhkZjIsIGMoImZyZXEyIiwgJ25JbmQyJyksYygia25vd25FTSIsICduSW5kJykpCn0KCndyaXRlLmNzdihlc3ROZSwiLi4vT3V0cHV0L05lL0pvcmRlLVJ5bWFuX05lLmVzdGltYXRlc19QV1MuY3N2IikKCiNlc3ROZTwtcmVhZC5jc3YoIi4uL091dHB1dC9OZS9Kb3JkZS1SeW1hbl9OZS5lc3RpbWF0ZXNfUFdTLmNzdiIsIHJvdy5uYW1lcyA9IDEpCmVzdE5lJHllYXI8LWFwcGx5KGVzdE5lWyJwb3AyIl0sMSwgZnVuY3Rpb24oeCkge2lmICh4PT0iOTYiKSB4PTE5OTYKICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKHg9PSIwNyIpIHg9MjAwNwogICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoeD09IjE3IikgeD0yMDE3fSkKCmdncGxvdChlc3ROZVtjKDEsNCw2KSxdLCBhZXMoeD15ZWFyLCB5PU5lKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MiwgY29sb3I9ImJsdWUiKSsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBDSS5sb3csIHltYXggPSBDSS51cCksIHdpZHRoID0gMC4yLCBjb2xvcj0iYmx1ZSIpKwogICAgZ2VvbV9wYXRoKGNvbG9yPSJibHVlIikreWxhYigiRXN0aWFtdGVkIE5lIikreGxhYigiWWVhciIpKwogICAgdGhlbWVfY2xhc3NpYygpK2dndGl0bGUoIlBXUyIpCmdnc2F2ZSgiLi4vT3V0cHV0L05lL0pvcmRlLVJ5bWFuX05lLmVzdGltYXRlcy5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMsIGRwaT0zMDApCgoKYGBgCgpgYGB7cn0Ka25pdHI6OmthYmxlKGVzdE5lKQpgYGAKCg==